class Vue {

    constructor(options) {
        //1. 保存数据
        this.$options = options
        this.$el = options.el
        this.$data = options.data

        //2. 将data添加到相应系统
        new Observer(this.$data)

        //3.代理this.$data的数据
        Object.keys(this.$data).forEach(key => {
            this._proxy(key)
        })

        //4. 处理el
        new Compiler(this.$el, this)
    }

    //定义代理
    _proxy(key) {
        Object.defineProperty(this, key, {
            configurable: true,
            enumerable: true,
            get() {
                return this.$data[key]
            },
            set(newValue) {
                this.$data[key] = newValue;
            },
        })
    }
}



//数据响应系统
class Observer {
    constructor(data) {
        this.data = data

        //基本数据类型或空 直接返回
        if (typeof data !== "object" || data === null) {
            return data
        }

        //遍历对象属性
        Object.keys(this.data).forEach(key => {
            //调用响应式系统
            this.defineReactive(this.data, key, this.data[key])
        })
    }

    //定义响应式
    defineReactive(target, key, value) {

        //每个属性对应一个dep实例 
        const dep = new Dep();

        //数据劫持
        Object.defineProperty(target, key, {

            enumerable: true,//可枚举,可遍历的

            configurable: true, //可更改的
            get() {

                /**
                 * 获取数据,会自动调用get方法,
                 * 把对应watcher实例,
                 * 添加到dep实例subs数组中
                 */
                if (Dep.target) {
                    dep.addSubs(Dep.target)
                }
                return value
            },

            set(newValue) {

                if (value !== newValue) {

                    value = newValue;

                    //通知watcher更新视图
                    dep.notify()
                }
            }
        })
    }

}


//定义发布者类
class Dep {
    constructor() {
        //初始化数组,存放watcher
        this.subs = []
    }

    //添加watcher方法
    addSubs(watcher) {
        this.subs.push(watcher)
    }

    //通知watcher更新视图方法
    notify() {
        this.subs.forEach(watcher => {
            watcher.updata()
        })
    }
}


//定义观察者类
class Watcher {
    constructor(node, name, vm) {
        this.node = node;
        this.name = name;
        this.vm = vm;

        //把watcher实例赋值给
        //Dep的target属性
        Dep.target = this

        this.updata();

        /**
         * 必须清空Dep target属性,
         * 只有初始化时调用一次,
         * 以后获取值时,防止重复添加watcher
         */
        Dep.target = null;

    }

    //更新视图方法
    updata() {
        //  获取属性,自动调用get方法
        this.node.nodeValue = this.vm[this.name]
    }
}

//定义正则,用来匹配mustache语法
const reg = /\{\{(.+)\}\}/

//定义Compiler类
class Compiler {
    constructor(el, vm) {

        //获取元素对象
        this.el = document.querySelector(el)


        this.vm = vm; //保存vue实例

        //获取片段对象
        this.frag = this._createFragment()

        //将片段对象添加到DOM中
        this.el.appendChild(this.frag)
    }

    //定义获取片段的方法
    _createFragment() {
        //创建片段对象
        const frag = document.createDocumentFragment()


        let child;

        /**
         * 本段代码相当于完成了 元素的剪切操作,
         * 将dom数中的元素,剪切到到片段中
         * 因为使用appendChid方法将原dom树中的节点添
         * 加到DocumentFragment中时，会删除原来的节点
         */

        //  child = this.el.firstChild.hasChildNodes()
        while (child = this.el.firstChild) {


            //解析每个节点
            this._compile(child)

            frag.appendChild(child)
        }

        return frag
    }

    //定义解析节点的方法
    _compile(node) {
        if (!node.hasChildNodes()) {
            //如果是元素节点
            if (node.nodeType == 1) {

                //attributes 属性返回指定节点的属性集合
                const attrs = node.attributes

                //如果该属性集合有 v-model
                if (attrs.hasOwnProperty("v-model")) {

                    //获取v-mode所在标签的值
                    const name = attrs['v-model'].nodeValue



                    //监听输入事件
                    node.addEventListener('input', event => {
                        console.log(this.vm[name])
                        console.log(event.target.value)
                        //????将事件对象的值赋值给vue实例
                        this.vm[name] = event.target.value;

                    })
                }
            }
            

            //如果是文本节点
            if (node.nodeType == 3) {


                if (reg.test(node.nodeValue)) {

                    //$1获取第一个分组内容
                    const name = RegExp.$1.trim()
                    console.log("mustache语法内容是->" + name)

                    //根据name 创建观察者对象
                    new Watcher(node, name, this.vm)
                }
            }
        }

        // console.log(node.hasChildNodes())
        // if (node.hasChildNodes()) {

        //     Array.from(node.children).forEach(item => {
        //         console.dir(item)
        //         this._compile(item.firstChild)
        //     })
        // }

        if(typeof(node.children) != "undefined" ) {
            Array.from(node.children).forEach(item => {
                console.dir(item.children)
                this._compile(item)
            })
        }
        



    }
}


